package org.mushroomdb.transaction;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Observable;
import java.util.Observer;

import org.mushroomdb.catalog.Column;
import org.mushroomdb.catalog.Register;
import org.mushroomdb.catalog.WriteBackRegister;
import org.mushroomdb.catalog.impl.RegisterImpl;
import org.mushroomdb.filemanagement.Page;

/**
 * @author Tomas
 * 
 * TODO To change the template for this generated type comment go to Window -
 * Preferences - Java - Code Style - Code Templates
 */
public class TransactionalRegister extends Observable implements
        TransactionalResource, WriteBackRegister {

    private WriteBackRegister register;

    private List values = new ArrayList();

    private List operation = new ArrayList();

    //Todo ver bien que hacer con esto
    private boolean inTrx = false;

    //TODO Check this
    //Ver como me pasan el registro
    public TransactionalRegister(WriteBackRegister register) {
        this.register = register;

    }

    public void onCommit() {
        ListIterator iter = this.operation.listIterator();
        while (iter.hasNext()) {
            Operation anOperation = (Operation) iter.next();
            String methodName = anOperation.getMethodName();
            Class[] parameterTypes = anOperation.getClasses();
            Object[] args = anOperation.getArgs();

            try {
                Method method = this.register.getClass().getMethod(methodName,
                        parameterTypes);
                method.invoke(this.register, args);
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.inTrx = false;
    }

    public void onRollback() {
        //vacio las lista de valores y de operaciones
        this.operation = new ArrayList();
        this.values = new ArrayList();
        this.inTrx = false;

    }

    public void onBeginTrx() {
        this.inTrx = true;
        int columnCount = this.register.getColumnCount();
        for (int i = 0; i < columnCount; i++) {
            Object value = this.register.getValue(i);
            this.values.add(i, value);
        }

    }

    public boolean isInTrx() {
        return this.inTrx;
    }

    public Object getValue(int columnIndex) {
        if (isInTrx()) {
            return this.values.get(columnIndex);
        } else
            return this.register.getValue(columnIndex);
    }

    public void setValue(int columnIndex, Object value) {
        if (isInTrx()) {
            Object[] parameters = { new Integer(columnIndex), value };
            Operation setValueOperation = new Operation("setValue", parameters);
            this.operation.add(setValueOperation);

            this.values.add(columnIndex, value);
        } else {
            this.register.setValue(columnIndex, value);
        }

    }

    public Iterator getColumns() {
        return this.register.getColumns();
    }

    public int getColumnIndex(Column column) {
        return this.register.getColumnIndex(column);
    }

    public int getColumnCount() {
        return this.register.getColumnCount();
    }

    public void setPage(Page page) {
        this.register.setPage(page);
    }

    public void setOffset(int offset) {
        this.register.setOffset(offset);
    }

    public int getOffset() {
        return this.register.getOffset();
    }

    public Page getPage() {
        return this.register.getPage();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mushroomdb.catalog.Register#remove()
     */
    public void remove() {
        // TODO Auto-generated method stub

    }

}
